<template>
  <div class="data-table">
    <!-- :height="tableHeight" -->
    <el-table
      ref="componentsTable"
      v-loading="loading"
      :data="tableData"
      :max-height="maxHeight"
      style="width: 100%"
      :border="border"
      :span-method="spanMethod"
      @selection-change="handleSelectionChange"
      @select-all="handleSelectAll"
      @row-click="jumpDetails"
      @sort-change="changeTabSort"
      @cell-dblclick="handleDbClick"
    >
      <template v-for="(col, index) in columns_data">
        <!-- 操作列/自定义列 -->
        <slot v-if="col.slot" :name="col.slot">
          <el-table-column v-if="col.slot === 'index'" type="index" :index="indexFun" width="60" label="序号" align="center" />
        </slot>
        <!-- 普通列 -->
        <el-table-column
          v-else
          :key="col.key + '' + index"
          :column-key="col.key"
          :prop="col.prop"
          :label="col.label"
          :width="col.width"
          :min-width="col.minWidth"
          align="center"
          :fixed="col.fixed"
          :sortable="col.sortable"
          show-overflow-tooltip
        >
          <template slot-scope="scope">
            <template v-if="(isEdit || (isDbEdit && dbClickData.property === col.prop && scope.$index == dbClickData.col_index)) && (!col.disabled && !scope.row.disabled)">
              <FormComponents :hidden-label="true" :item-obj="col" :form="scope.row" :is-edit="true" class="fromisedit" @blur="() => handleBlur(scope.row, col)" />
            </template>
            <template v-else>
              <span v-if="col.type === 'remoteSelect'" :class="col.class && classFun(col.class, scope.row[col.prop])">
                {{ scope.row[col.propValue] }}
              </span>
              <span v-else-if="col.formatter" :class="col.class && classFun(col.class, scope.row[col.prop])" v-html="scope.row[col.formatter]" />
              <span v-else-if="col.format" :class="col.class && classFun(col.class, scope.row[col.prop])">
                {{ formatText(col, scope.row).data }}
              </span>
              <span v-else>{{ scope.row[col.prop] }}</span>
            </template>
          </template>
        </el-table-column>
      </template>
      <div slot="empty">
        <slot name="empty">
          <el-empty description="暂无数据" />
        </slot>
      </div>
    </el-table>
    <!-- 是否调用分页 -->
    <div class="clearfix" style="text-align: right;">
      <el-pagination
        v-if="isPagination"
        style="overflow: hidden"
        background
        layout="slot, total, sizes, prev, pager, next"
        :current-page.sync="pageNum"
        :page-size.sync="pageSize"
        :page-sizes="[10, 15, 20, 25, 30]"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>
<script>
/**
 * isDbEdit全局双击编辑
 * dbClickData 双击单元格时，单元格内数据，锁定该单元格进行编辑
 * columns_data里面disabled和tableData里面disabled也可以控制是否编辑
 */
import request from '@/utils/request.js'
// 选择相关
import selectMixin from './mixin/select.js'
import FormComponents from '@/components/Table/components/form.vue'
export default {
  name: 'TabtableList',
  components: {
    FormComponents
  },
  mixins: [selectMixin],
  props: {
    columns: {
      type: Array,
      required: true,
      default() {
        return []
      }
    },
    data: {
      type: Array,
      default() {
        return []
      }
    },
    /**
     * 接口传参配置
     */
    params: {
      type: Object,
      default() {
        return {}
      }
    },
    // 列表请求路径
    url: {
      type: String,
      default: ''
    },
    returnData: {
      type: [Function, String],
      default: ''
    },
    // 是否分页
    isPagination: {
      type: Boolean,
      default: true
    },
    pramsWatch: {
      type: Boolean,
      default: false
    },
    headSearch: {
      type: Boolean,
      default: true
    },
    methodType: {
      type: String,
      default: 'get'
    },
    maxHeight: {
      type: String || Number,
      default: null
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    isDbEdit: {
      type: Boolean,
      default: false
    },
    border: {
      type: Boolean,
      default: true
    },
    spanMethod: {
      type: Function
    },
    // 待完善
    // 确认 在什么条件下出席确认框
    // 1、校验不通过，例子：输入框中的值为空
    // 2、强制弹出，只要修改后的值与克隆值不同，则直接弹出
    confirm: {
      type: Object,
      default: () => {
        return {
          open: false
        }
      }
    }
  },
  data() {
    return {
      columns_data: [],
      tableData: [],
      pageNum: 1,
      pageSize: 10,
      total: 0,
      loading: false,
      // 已选择数据
      selectionData: [],
      originalParams: {},
      watchParams: {},
      sortParams: {},
      dbClickData: {},
      dbCloneData: {}
    }
  },
  watch: {
    data: {
      handler(v) {
        this.handleDataTable(v)
      },
      immediate: true
    },
    columns: {
      handler(v) {
        this.columns_data = this.$_.cloneDeep(v).map((c, index) => {
          c.itemprop = 'tableData.' + index + '.' + c.prop
          c.key = new Date().getTime() + ((Math.random() * 1000).toFixed(0) + index)
          return c
        })
      },
      deep: true,
      immediate: true
    },
    params: {
      handler(v) {
        this.watchParams = JSON.parse(JSON.stringify(v))
        this.originalParams = JSON.parse(JSON.stringify(v))
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    handleDataTable(data) {
      this.tableData = data.map((r, index) => {
        r.col_index = index
        return r
      })
    },
    indexFun(index) {
      return index + this.pageSize * (this.pageNum - 1) + 1
    },
    // 单页个数
    handleSizeChange(val) {
      this.pageSize = val
      this.getList()
    },
    // 跳页
    handleCurrentChange(val) {
      this.pageNum = val
      this.getList()
    },
    setParamsBefore() {
      var t = {
        pageSize: this.pageSize,
        pageNum: this.pageNum,
        ...this.watchParams,
        ...this.sortParams
      }
      return t
    },
    changeTabSort(column, prop, v) {
      if (column.order) {
        var order = column.order === 'descending' ? 'desc' : 'asc'
        this.sortParams = {
          sortName: column.prop.replace(/([A-Z])/g, '_$1').toLowerCase(),
          sortOrder: order
        }
      } else {
        this.sortParams = {}
      }

      this.pageNum = 1
      this.getList()
    },
    // 列表查询
    getList() {
      if (!this.url) return
      this.loading = true
      this._request(this.setParamsBefore())
        .then(r => {
          var res = r.data
          var _tableData = []
          if (r.code === 0 || r.code === 200) {
            if (typeof this.returnData === 'function') {
              _tableData = this.returnData(res)
            } else {
              _tableData = res.data.list
            }
            this.handleDataTable(_tableData)
            this.total = res.total
            if (this.selectionConfig.rowBoolean) {
              this.diffSelect = []
              this.toggleRowForEarch(this.selectionData)
            }

            this.$refs.componentsTable.doLayout()
          }
          this.loading = false
        })
        .catch(e => {
          console.log(e)
          this.handleDataTable([])
          this.loading = false
        })
    },
    _request(data) {
      if (this.methodType === 'post') {
        return request.post(this.url, data)
      } else {
        return request.get(this.url, data)
      }
    },
    jumpDetails(row, column) {
      if (column.type === 'selection') {
        const componentsTable = this.$refs.componentsTable
        // selection 存在时，selection 的 selectable 返回结果为 true 时，才能选中
        // selection 不存在时，直接选中
        const selection = componentsTable.columns.find(x => x.type === 'selection')
        if (selection && selection.selectable && typeof selection.selectable === 'function') {
          if (selection.selectable(this.tableData[row.sf_index])) {
            return componentsTable.toggleRowSelection(this.tableData[row.sf_index])
          }
        } else if (!selection) {
          return componentsTable.toggleRowSelection(this.tableData[row.sf_index])
        }
        return
      }
      if (column.label && column.label === '操作') {
        return
      }
      this.$emit('jumpDetails', row, column)
    },
    handleSearch() {
      this.pageNum = 1
      this.getList()
    },
    handleSearchParams(v) {
      this.watchParams = v
      this.pageNum = 1
      this.getList()
    },
    handleReset() {
      this.watchParams = JSON.parse(JSON.stringify(this.originalParams))
      this.pageNum = 1
      this.getList()
    },
    classFun(funtionOrString, param) {
      var result = funtionOrString
      if (funtionOrString) {
        if (typeof funtionOrString === 'function') {
          return funtionOrString(param)
        } else if (typeof funtionOrString === 'string') {
          return funtionOrString
        }
      }
      return result
    },
    handleDbClick(row, column, cell, event) {
      // 定位双击位置
      let tr = 0
      let td = 0
      let cellData = column.id.split('_')
      tr = parseInt(cellData[1]) - 1
      td = parseInt(cellData[3]) - 1
      this.dbClickData = {
        tr,
        td,
        ...column,
        col_index: row.col_index
      }
      // 先克隆一份原本数据
      this.dbCloneData = this.$_.cloneDeep(row)
    },
    handleBlur(row, col) {
      // 值相同的时候，不做任何操作
      if (row[col.prop] === this.dbCloneData[col.prop]) {
        this.handleCancelBlur()
        return
      }
      // 当输入的数据为空时，替换原数据
      if (row[col.prop] === null || row[col.prop] === '' || row[col.prop] === undefined) {
        try {
          this.$set(this.tableData[this.dbClickData.col_index], col.prop, this.dbCloneData[col.prop])
          this.handleCancelBlur()
        } catch (error) {
          throw new Error('对应的 prop 不存在，或者该行数据出现错误')
        }
        return
      }
      this.$emit('blur', {
        data: this.dbClickData,
        row, col
      })
    },
    handleCancelBlur() {
      this.dbClickData = {}
    }
  }
}
</script>
<style lang="scss">
.data-table .el-table .el-table__header-wrapper th,
.data-table .el-table .el-table__fixed-header-wrapper th {
  background-color: #f8f8f9 !important;
}
</style>
